﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Diagnostics;

namespace DynamicProperties.Tests
{
	[TestClass]
	public class BasicTests
	{
		DynamicProperty<string, int> testProperty1 = new DynamicProperty<string, int>("Test property 1");
		
		[TestMethod]
		public void StringBasicSetGet()
		{
			// basic property usage - set specific value / get same value
			int propertyValue = 123;

			string obj1 = "ABC1";

			testProperty1.Set(obj1, propertyValue);
			var propertyValueRead = testProperty1.Get(obj1);
	
			Assert.AreEqual(propertyValue, propertyValueRead);
		}

		[TestMethod]
		public void StringBasicSetGetMultiple()
		{
			// basic property usage - set multiple properties / read multiple properties
			int propertyValue = 123;
			int propertyValue2 = 246;
			
			string obj1 = "ABC2";

			testProperty1.Set(obj1, propertyValue);
			Assert.AreEqual(propertyValue, testProperty1.Get(obj1));
			testProperty1.Set(obj1, propertyValue2);
			Assert.AreEqual(propertyValue2, testProperty1.Get(obj1));
		}

		DynamicProperty<object, int> testProperty2 = new DynamicProperty<object, int>("Test property 2");
		
		[TestMethod]
		public void ObjectArraySetGet()
		{
			// assign different value to each item in array
			int cnt = 50;

			var array = Enumerable.Range(1, cnt).Select(i => new object()).ToArray();

			// set values
			for (int i = 0; i < array.Length; i++)
			{
				testProperty2.Set(array[i], i);
			}

			// get values
			for (int i = 0; i < array.Length; i++)
			{
				Assert.AreEqual(i, testProperty2.Get(array[i]));
			}
		}

		[ExpectedException(typeof(ArgumentNullException))]
		[TestMethod]
		public void NullObjectSetProperty()
		{
			// should invoke exception
			testProperty1.Set(null, 0);
		}

		[ExpectedException(typeof(ArgumentNullException))]
		[TestMethod]
		public void NullObjectGetProperty()
		{
			// should invoke exception
			testProperty1.Get(null);
		}

		[TestMethod]
		public void ObjectTryGetEmpty()
		{
			string obj1 = "ABBCDEF123456789";

			// read
			int r;
			bool result = testProperty1.TryGet(obj1, out r);
			Assert.IsFalse(result);
		}

		[TestMethod]
		public void ObjectSetTryGet()
		{
			string obj1 = "XYZCDEF12346548949";
			int obj1_val = 123;
			
			// set
			testProperty1.Set(obj1, obj1_val);

			// read
			int r;
			bool result = testProperty1.TryGet(obj1, out r);
			Assert.IsTrue(result);
			Assert.AreEqual(obj1_val, r);
		}


		[ExpectedException(typeof(ArgumentNullException))]
		[TestMethod]
		public void ObjectTryGetNull()
		{
			int r;
			testProperty1.TryGet(null/*target*/, out r);
		}

		DynamicProperty<object, object> testProperty3 = new DynamicProperty<object, object>("Test property 3");

		[TestMethod]
		public void ObjectSetNullGetNull()
		{
			var obj1 = new object();
			var obj1_val1 = new object();

			// ensure value (default)
			Assert.IsNull(testProperty3.Get(obj1));

			// set value
			testProperty3.Set(obj1, obj1_val1);

			// ensure value
			Assert.AreSame(obj1_val1, testProperty3.Get(obj1));

			// set value
			testProperty3.Set(obj1, null);

			// ensure value
			Assert.IsNull(testProperty3.Get(obj1));
		}

		DynamicProperty<object, object> testProperty4 = new DynamicProperty<object, object>("Test property 4", new object() /* default */);

		[TestMethod]
		public void ObjectSetNullGetNullWithDefaultNonNull()
		{
			var obj1 = new object();

			// ensure value (default)
			Assert.IsNotNull(testProperty4.Get(obj1));
			
			// set value
			testProperty4.Set(obj1, null);

			// ensure value
			Assert.IsNull(testProperty4.Get(obj1));
		}
		
	}
}
